package com.fabula.android.timeline.sync;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.SocketException;

import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;

import com.fabula.android.timeline.utilities.Constants;

import android.util.Log;

@SuppressWarnings("unused")
/**
 * Abstract class that handles a transfor to or from an FTP server
 * It should be instanciated as either FTPUpload or FTPDownload:
 * 	- FTPUpload if you want to upload a file
 *  - FTPDownload if you want to download a file
 *  
 * What server is used is defined in the utilities.Constants
 * @author Mads
 *
 */
public abstract class FTPTransfer implements Runnable{
	public String filepath;
	public String filename;
	public File file;
	
	protected void log(String arg){
		Log.i("FTP ",arg);
	}
	protected void err(String arg){
		Log.e("FTPERROR ",arg);
	}
	
	/**
	 * Runnable method used by the transfer function to safeguard against network on main thread.
	 * Should not be used!
	 */
	public void run() {
		try {
			FTPClient ftp;
			boolean loggedin;

			ftp = new FTPClient();
			
			log("Attempting to connect");
			try {
				ftp.connect(Constants.FTP_SERVER_URL, Constants.FTP_PORT);
			} catch (SocketException e1) {
				err("SOCKETEXCEPTION ON CONNECT");
				e1.printStackTrace();
				file = null;
			}
			log("Connected to FTP server: "+ftp.isConnected());

			ftp.enterLocalPassiveMode();
			log("Entered local passive mode (Android devices will generally be behind firewall or NAT)");

			loggedin = ftp.login(Constants.FTP_ACCOUNT_NAME, Constants.FTP_ACCOUNT_PASSWORD);
			log("Logged in: "+loggedin);
			if(!loggedin){
				err("Couldn't log in, aborting");
				file = null;
			}
			
			ftp.setFileType(FTP.BINARY_FILE_TYPE);

			file = transact(filepath, filename, ftp);

			log("Logging out");
			ftp.logout();
			log("Disconnecting");
			ftp.disconnect();
			
		} catch (IOException e) {
			err("IOEXCETPION");
			e.printStackTrace();
		} catch (Exception e) {
			err("EXCETPION");
			e.printStackTrace();
		}
	}
	
	/**
	 * Performs a transfar to or from the FTP server.
	 * FTPUpload will upload filepath\filename to the server
	 * FTPDownload will download filename from the FTP server and store it at filepath\filename
	 * 
	 * @param filepath
	 * @param filename
	 * @return
	 */
	public File transfer(String filepath, String filename){
		
		this.filepath = filepath;
		this.filename = filename;
		Thread thread = new Thread(this,"Avoid network on main thread exception");
		thread.start();
		try {
			thread.join();
		} catch (InterruptedException e) {
			err("Interrupted");
			e.printStackTrace();
		}
		return file;
	}

	protected abstract File transact(String filepath, String filename, FTPClient ftp) throws IOException;
}

class FTPUpload extends FTPTransfer{

	@Override
	protected File transact(String filepath, String filename, FTPClient ftp) throws IOException {
		log("Path: "+filepath);
		log("Name: "+filename);
		File file;
		FileInputStream fileInputStream;
		boolean store;
		log("Opening file for input");
		file = new File(filepath);
		log("Absolute file path: "+file.getAbsolutePath());
		log("File exists: "+file.exists());
		if(!file.exists()){
			err("Can't send a file that doesn't exist");
			return file;
		}
		log("Creating fileinput stream");
		fileInputStream = new FileInputStream(file);
		log("Sending file");
		store = ftp.storeFile(filename, fileInputStream);
		log("Sent file: "+store);
		if(!store)err("Couldn't send file");
		return file;
	}
}

class FTPDownload extends FTPTransfer{

	@Override
	protected File transact(String filepath, String filename, FTPClient ftp) throws IOException {
		log("Path: "+filepath);
		log("Name: "+filename);
		File file;
		FileOutputStream fileOutputStream;
		boolean fetch;
		log("Opening file for output");
		file = new File(filepath);
		if(file.exists()){
			log("File already exists");
			//return file;
		}
		log("Creating file output stream for output file");
		fileOutputStream = new FileOutputStream(file);
		log("Retrieving file");
		fetch = ftp.retrieveFile(filename, fileOutputStream);
		log("Retrieved file: "+fetch);
		if(!fetch){
			err("Couldn't retrieve file");
			file.delete();
			return null;
		}
		return file;
	}
}
